#include "Thread.h"

#include <sys/syscall.h>
#include <cassert>
#include <sys/prctl.h>

#include "../log/Logging.h"

namespace CurrentThread {
    void cacheTid() {
        if (cacheTid_ == 0) {
            cacheTid_ = static_cast<pid_t>(::syscall(SYS_gettid));
            t_tidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", cacheTid_);
        }
        // 发现没有缓存当前线程的唯一标识的时候, 就缓存当前线程的唯一标识
    }

    bool isMainThread() {
        return getTid() == ::getpid();
    }
}

namespace detail {
    struct ThreadData {
        // 线程数据集合, 封装了线程相关信息
        typedef Thread::ThreadFunc ThreadFunc;
        ThreadFunc func_;
        // 线程对应的执行函数
        string name_;
        // 线程名称
        pid_t *tid_;
        // 线程标识符
        CountDownLatch *latch_;
        // 锁

        ThreadData(ThreadFunc func,
                   string name,
                   pid_t *tid,
                   CountDownLatch *latch)
                : func_(std::move(func)),
                  name_(std::move(name)),
                  tid_(tid),
                  latch_(latch) {}

        void runInThread() {
            *tid_ = CurrentThread::getTid();
            // 调用Thread缓存到当前线程的tid
            tid_ = NULL;
            latch_->countDown();
            // 启用倒计时, 调用之后如果为0的话就会唤醒wait的线程
            latch_ = NULL;
            CurrentThread::t_threadName = name_.empty() ? "myThread" : name_.c_str();
            ::prctl(PR_SET_NAME, CurrentThread::t_threadName);
            // 这里的函数调用是将 CurrentThread::t_threadName 赋值给进程名称
            try {
                func_();
                // 执行线程操作
                CurrentThread::t_threadName = "finished";
            }
                /*    catch (const Exception &ex) {
                        CurrentThread::t_threadName = "crashed";
                        fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());
                        fprintf(stderr, "reason: %s\n", ex.what());
                        fprintf(stderr, "stack trace: %s\n", ex.stackTrace());
                        abort();
                    }*/
            catch (const std::exception &ex) {
                CurrentThread::t_threadName = "crashed";
                fprintf(stderr, "exception caught in Thread %s\n", name_.c_str());
                fprintf(stderr, "reason: %s\n", ex.what());
                abort();
            }
            catch (...) {
                CurrentThread::t_threadName = "crashed";
                fprintf(stderr, "unknown exception caught in Thread %s\n", name_.c_str());
                throw; // rethrow
            }
        }
    };

    void *startThread(void *obj) {
        ThreadData *data = static_cast<ThreadData *>(obj);
        data->runInThread();
        delete data;
        return NULL;
    }

}  // namespace detail

AtomicInt32 Thread::numCreated_;

Thread::Thread(ThreadFunc func, string n)
        : started_(false),
          joined_(false),
          pthreadId_(0),
          tid_(0),
          func_(std::move(func)),
          name_(std::move(n)),
          latch_(1) {
    setDefaultName();
    // 这里就是设置初始化的名称而已, 没什么特别的
}

Thread::~Thread() {
    if (started_ && !joined_) {
        pthread_detach(pthreadId_);
    }
}

void Thread::setDefaultName() {
    if (name_.empty()) {
        int num = numCreated_.incrementAndGet();
        char buf[32];
        snprintf(buf, sizeof buf, "Thread%d", num);
        name_ = buf;
    }
}

/**
 * 启动线程
 */
void Thread::start() {
    assert(!started_);
    // 查看当前是否正在开启线程
    started_ = true;
    // FIXME: move(func_)
    detail::ThreadData *data = new detail::ThreadData(func_, name_, &tid_, &latch_);
    // 初始化线程参数
    if (pthread_create(&pthreadId_, NULL, &detail::startThread, data)) {
        // 创建线程, 如果创建成功返回 0, 当放回非 0 值的时候说明创建失败
        // 释放掉我们配置的线程参数
        started_ = false;
        delete data; // or no delete?
        LOG_SYSFATAL << "`pthread_create 调用失败";
        /* 日志记录 */
    } else {
        latch_.wait();
        // 将当前进程进入等待状态, 倒计时计时器初始化的值为线程的数量, 只有当所有的线程初始化完毕后
        // 当前线程才会被唤醒
        assert(tid_ > 0);
    }
}

/**
 * 调用后会让程序一直阻塞直到这个线程执行完毕才会返回
 * @return 返回值为 0 代表线程正常结束, 返回值为非0值标识发生了错误
 */
int Thread::join() {
    assert(started_);
    assert(!joined_);
    joined_ = true;
    return pthread_join(pthreadId_, NULL);
}